using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;

namespace OrbitOne.CRMLyncInfoDashboard.CRM.Plugins
{
    public abstract class SearchFieldProvider
    {
        protected readonly Regex m_phoneNumberCleanup = new Regex(@"\W");

        public IOrganizationService Sdk { get; set; }

        public string CalculateSearchFieldValue(Entity tempEntity, IPluginExecutionContext pluginContext)
        {
            var searchValues = GetSearchValues(tempEntity, pluginContext);
            return string.Join(",", searchValues.Where(s => !string.IsNullOrEmpty(s)));
        }

        protected abstract CrmField[] CalculationFields { get; }

        protected object GetSearchValue(Entity targetEntity, Entity entity, string attributeName)
        {
            return targetEntity.Contains(attributeName)
                       ? targetEntity[attributeName]
                       : (entity.Contains(attributeName)
                              ? entity[attributeName]
                              : null);
        }

        protected string GetEmailAddressSearchValue(Entity tempEntity, Entity entity, string fieldName)
        {
            var searchValue = GetSearchValue(tempEntity, entity, fieldName);
            return searchValue != null
                       ? searchValue.ToString()
                       : "";
        }

        protected string GetPhoneNumberSearchValue(Entity tempEntity, Entity entity, string fieldName)
        {
            var searchValue = GetSearchValue(tempEntity, entity, fieldName);
            return searchValue
                .CleanupNonAlphanumeric(m_phoneNumberCleanup);
        }

        protected Entity PopulateEntityFields(Entity tempEntity, CrmField[] fields, IPluginExecutionContext pluginContext)
        {
            if(IsCreated(pluginContext))
            {
                return tempEntity;
            }
            var fieldList = fields.Select(f => f.Value).ToArray();
            return Sdk.Retrieve(tempEntity.LogicalName, tempEntity.Id, new ColumnSet(fieldList));
        }

        private bool IsCreated(IPluginExecutionContext pluginContext)
        {
            return pluginContext.MessageName == "Create";
        }

        protected string[] GetSearchValuesList(Entity tempEntity, Entity entity)
        {
            return CalculationFields.Select(cf => cf.Type == CrmFieldType.PhoneNumber
                                                      ? GetPhoneNumberSearchValue(tempEntity, entity, cf.Value)
                                                      : GetEmailAddressSearchValue(tempEntity, entity, cf.Value))
                .ToArray();
        }

        protected virtual string[] GetSearchValues(Entity tempEntity, IPluginExecutionContext pluginContext)
        {
            var entity = PopulateEntityFields(tempEntity, CalculationFields, pluginContext);
            return GetSearchValuesList(tempEntity, entity);
        }
    }
}